﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using ACSR.Controls.ThirdParty.Python;
using ACSR.PythonScripting;
using EnvDTE;
using Extensibility;
using MEFAddin;
using MEFAddin.Interfaces;

namespace PyAddIn.Controllers
{
    [Export(typeof(IAddInController))]
    public class PythonAddinController : MEFController
    {
        IToolWindowContext _debuggerHostWindow;

        dynamic _handler;

        public event EventHandler OnScriptReload;

        public void ReloadScript()
        {
            this.OnScriptReload(this, new EventArgs());
        }

        ScriptMonitor _monitor;

        void _monitor_OnScriptUnLoading(object sender, ScriptMonitorEventArgs e)
        {
            try
            {

                _handler.UnhookEvents(this);
            }
            catch (Exception x)
            {
                LoggingAdapter.LogError("Error _monitor_OnScriptUnLoading: " + x.ToString());
            }
        }

        protected override void InternalOnConnectionCompleted()
        {
            try
            {
                InitDebuggerWindow();
                LoadScriptEngine();
                _handler.OnConnection(this);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.OnConnectionCompleted: " + e.ToString());
            }
        }

        protected override void InternalQueryStatus(string CmdName, vsCommandStatusTextWanted NeededText, ref vsCommandStatus StatusOption, ref object CommandText)
        {
            try
            {

                dynamic results = _handler.QueryStatus(CmdName, NeededText, StatusOption, CommandText);
                StatusOption = results[0];
                CommandText = results[1];
                return;
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.QueryStatus: " + e.ToString());
            }

        }

        protected override void InternalExec(string CmdName, vsCommandExecOption ExecuteOption, ref object VariantIn, ref object VariantOut, ref bool Handled)
        {
            try
            {
                _handler.Exec(CmdName, ExecuteOption, VariantIn, VariantOut, Handled);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.Exec: " + e.ToString());
            }
        }

        protected override void InternalOnBeginShutdownCompleted(ref Array custom)
        {
            try
            {
                _handler.OnBeginShutdown(custom);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.OnBeginShutdown: " + e.ToString());
            }
        }

        protected override void InternalOnStartupCompleteCompleted(ref Array custom)
        {
            try
            {
                InitDebuggerWindow();
                _debuggerHostWindow.Window.Visible = true;
                _handler.OnStartupComplete(custom);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.OnStartupComplete: " + e.ToString());
            }

        }

        protected override void InternalOnAddInsUpdateCompleted(ref Array custom)
        {
            try
            {
                _handler.OnAddInsUpdate(custom);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.OnAddInsUpdate: " + e.ToString());
            }

        }

        protected override void InternalOnDisconnectionCompleted(ext_DisconnectMode disconnectMode, ref Array custom)
        {
            try
            {
                _handler.OnDisconnection(disconnectMode, ref custom);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.OnDisconnection: " + e.ToString());
            }

        }

        void _monitor_OnScriptLoading(object sender, ScriptMonitorEventArgs e)
        {
            try
            {
                //   e.Context.SetVariable("ObjectExplorer", _objectExplorer);
            }
            catch (Exception x)
            {
                LoggingAdapter.LogError("Error _monitor_OnScriptLoading: " + x.ToString());
            }


        }

        void _monitor_OnEngineMessage(object sender, string Message)
        {
            LoggingAdapter.LogMessage(Message);
        }

        void LoadScriptEngine()
        {
            try
            {
                if (_monitor == null)
                {
                    var scriptDirectory = Path.Combine(this.WorkingDirectory, "Scripts");
                    var scriptFileName = Path.Combine(scriptDirectory, "SSMSAddin.py");
                    _monitor = new ScriptMonitor(scriptFileName);

                    _monitor.OnScriptLoading += new ScriptMonitorEvent(_monitor_OnScriptLoading);
                    _monitor.OnScriptLoaded += new ScriptMonitorEvent(_monitor_OnScriptLoaded);
                    _monitor.OnScriptUnLoading += new ScriptMonitorEvent(_monitor_OnScriptUnLoading);
                    _monitor.OnEngineMessage += new MessageEvent(_monitor_OnEngineMessage);
                    _monitor.Activate();
                }
            }
            catch (Exception x)
            {
                LoggingAdapter.LogError("Error LoadScriptEngine: " + x.ToString());
            }
        }

        void _monitor_OnScriptLoaded(object sender, ScriptMonitorEventArgs e)
        {
            try
            {

                LoggingAdapter.LogMessage("Script loading...");
                _handler = e.Context.Scope.CreateDefaultConsumer();
                _handler.HookEvents(this.AddInContext, this);
                LoggingAdapter.LogMessage("Script Loaded");
            }
            catch (Exception x)
            {
                LoggingAdapter.LogError("Error _monitor_OnScriptLoaded: " + x.ToString());
            }
        }

        private void InitDebuggerWindow()
        {

            try
            {
                if (_debuggerHostWindow == null)
                {
                    var pypad = new UcPyPad();
                    pypad.ActiveWindow.Presenter.SetVariable("Controller", this);
                    pypad.ActiveWindow.Presenter.SetVariable("Adapter", this);
                    _debuggerHostWindow = this.WindowAdapter.FindOrCreateHostWindow(pypad, "IronPython Interactive", "E6AD7E34-34CA-47E7-95EE-7C05D4128580");
                }

            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error InitDebuggerWindow: " + e.ToString());
            }
        }


        protected override void InternalCommandEvents_AfterExecute(string Guid, int ID, object CustomIn, object CustomOut)
        {
            try
            {

                _handler.CommandEvents_AfterExecute(Guid, ID, CustomIn, CustomOut);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.CommandEvents_AfterExecute: " + e.ToString());
            }
        }

        protected override void InternalCommandEvents_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
        {
            try
            {
                _handler.CommandEvents_BeforeExecute(Guid, ID, CustomIn, CustomOut, ref CancelDefault);
            }
            catch (Exception e)
            {
                LoggingAdapter.LogError("Error _handler.CommandEvents_BeforeExecute: " + e.ToString());
            }
        }
    }
}
